#include "stdafx.h"
#include "OutLookHelper.h"
#include "PECore.h"
#include "AppTools.h"
#include "MiniHttpd.h"
#include "SettingHelper.h"
#include "afxinet.h"


CRITICAL_SECTION cs4Stat;
HANDLE g_hStatThread = 0;
CMiniHttpd *g_miniHttpd;
int g_iPCPort = 20000;
TCHAR *g_pChartData = NULL;

#define PE_MAX_BUF_LEN			(1024 * 1024 * 10)
void FreeAllList();

extern int g_iExport;
extern TCHAR szExportFileName[255];
DWORD WINAPI StatProcessT(LPVOID  lparam)
{
	::CoInitialize(NULL);
	EnterCriticalSection(&cs4Stat);
	STAT_ARG *pArg = (STAT_ARG*)lparam;

	COutLookHelper::LogIn(NULL);
	COutLookHelper::StatMailNow(pArg->ftStartTime,pArg->ftEndTime,pArg->iStatType);
	COutLookHelper::LogOut();

	if (g_iExport)
	{
		ExportData(pArg->ftStartTime,pArg->ftEndTime,pArg->iStatType,szExportFileName);
	}

	GenChartData(pArg->ftStartTime,pArg->ftEndTime,pArg->iStatType);
	extern HWND g_hMainWnd;
	::PostMessage(g_hMainWnd,WM_STAT_DONE,(WPARAM)pArg->iStatType,0);

	free(pArg);

	FreeAllList();

	LeaveCriticalSection(&cs4Stat);

	return PE_RET_OK;
}


void Init()
{
	InitializeCriticalSectionAndSpinCount(&cs4Stat,0x80000400);
	InitLog();

	StartMiniHttpd();


}

void DeInit()
{
	g_miniHttpd->Close();
	delete g_miniHttpd;

	WaitForSingleObject(g_hStatThread,1000 * 60 * 3);//wait 3 minutes before shutdown
}


void StartStatProcess(FILETIME &ftStartTime,FILETIME &ftEndTime,int iStatType)
{
	STAT_ARG *pArg = (STAT_ARG*)calloc(1,sizeof(STAT_ARG));
	pArg->ftStartTime = ftStartTime;
	pArg->ftEndTime = ftEndTime;
	pArg->iStatType = iStatType;

	g_hStatThread = CreateThread(NULL,0,StatProcessT,(LPVOID)pArg,0,0);
}


extern list<STAT_ITEM*>  g_YearSentStatList;
extern list<STAT_ITEM*>  g_YearRecvStatList;

extern list<STAT_ITEM*>  g_MonthSentStatList;
extern list<STAT_ITEM*>  g_MonthRecvStatList;

extern list<STAT_ITEM*>  g_DaySentStatList;
extern list<STAT_ITEM*>  g_DayRecvStatList;

extern list<STAT_ITEM*>  g_HourSentStatList;
extern list<STAT_ITEM*>  g_HourRecvStatList;

extern list<SENDER_ITEM*> g_TopSenderList;
extern list<SENDER_ITEM*> g_TopReceverList;


void FreeStatList(list<STAT_ITEM*>  &statList)
{
	list<STAT_ITEM*>::iterator it;
	for (it = statList.begin(); it != statList.end(); ++it)
	{ 
		STAT_ITEM *pItem = (STAT_ITEM*)*it;
		free(pItem);
	}

	statList.clear();
}

void FreeSenderList(list<SENDER_ITEM*>  &senderList)
{
	list<SENDER_ITEM*>::iterator it;
	for (it = senderList.begin(); it != senderList.end(); ++it)
	{ 
		SENDER_ITEM *pItem = (SENDER_ITEM*)*it;
		free(pItem);
	}

	senderList.clear();
}

void FreeAllList()
{
	FreeStatList(g_YearSentStatList);
	FreeStatList(g_YearRecvStatList);

	FreeStatList(g_MonthSentStatList);
	FreeStatList(g_MonthRecvStatList);

	FreeStatList(g_DaySentStatList);
	FreeStatList(g_DayRecvStatList);

	FreeStatList(g_HourSentStatList);
	FreeStatList(g_HourRecvStatList);

	FreeSenderList(g_TopSenderList);
	FreeSenderList(g_TopReceverList);
}

void TimeT2FileTime(time_t t1,FILETIME &ft)
{
	memcpy(&ft,&t1,sizeof(FILETIME));
}

void TimeT2SystemTime(time_t t1,SYSTEMTIME &st)
{
	FILETIME ftTmp;
	TimeT2FileTime(t1,ftTmp);
	FileTimeToSystemTime(&ftTmp,&st);
}

void SystemTime2TimeT(SYSTEMTIME &st,time_t &t1)
{
	FILETIME ftTmp = {0};
	SystemTimeToFileTime(&st,&ftTmp);
	memcpy(&t1,&ftTmp,sizeof(FILETIME));
}

time_t GetNextTime(int iStatType,time_t curTime)
{
	SYSTEMTIME stTmp;
	TimeT2SystemTime(curTime,stTmp);

	time_t nextTime = 0;

	if (iStatType == STAT_TYPE_BY_YEAR)
	{
		stTmp.wYear += 1;
		SystemTime2TimeT(stTmp,nextTime);
	}
	else if (iStatType == STAT_TYPE_BY_MONTH)
	{
		if (stTmp.wMonth < 12)
		{
			stTmp.wMonth += 1;
		}
		else
		{
			stTmp.wYear += 1;
			stTmp.wMonth = 1;
		}
		SystemTime2TimeT(stTmp,nextTime);
	}
	else if (iStatType == STAT_TYPE_BY_DAY)
	{
		nextTime = curTime + (time_t)ONE_SECOND * 60 * 60 * 24;
	}
	else if (iStatType == STAT_TYPE_BY_HOUR)
	{
		nextTime = curTime + (time_t)ONE_SECOND * 60 * 60;
	}

	return nextTime;
}

void GetTimeString(int iStatType,time_t curTime,TCHAR *szTime)
{
	SYSTEMTIME stTmp;
	TimeT2SystemTime(curTime,stTmp);

	if (iStatType == STAT_TYPE_BY_YEAR)
	{
		_stprintf(szTime,_T("'%d'"),stTmp.wYear);
	}
	else if (iStatType == STAT_TYPE_BY_MONTH)
	{
		_stprintf(szTime,_T("'%d-%d'"),stTmp.wYear,stTmp.wMonth);
	}
	else if (iStatType == STAT_TYPE_BY_DAY)
	{
		_stprintf(szTime,_T("'%d-%d'"),stTmp.wMonth,stTmp.wDay);
	}
	else if (iStatType == STAT_TYPE_BY_HOUR)
	{
		_stprintf(szTime,_T("'%d'"),stTmp.wHour);
	}

}

int IsSameRange(int iStatType,SYSTEMTIME &stCur,SYSTEMTIME &stTmp)
{
	if (stCur.wYear != stTmp.wYear)
	{
		return PE_RET_FAIL;
	}

	if (iStatType == STAT_TYPE_BY_YEAR)
	{
		return PE_RET_OK;
	}

	if (stCur.wMonth != stTmp.wMonth)
	{
		return PE_RET_FAIL;
	}

	if (iStatType == STAT_TYPE_BY_MONTH)
	{
		return PE_RET_OK;
	}

	if (stCur.wDay != stTmp.wDay)
	{
		return PE_RET_FAIL;
	}

	if (iStatType == STAT_TYPE_BY_DAY)
	{
		return PE_RET_OK;
	}

	if (stCur.wHour != stTmp.wHour)
	{
		return PE_RET_FAIL;
	}

	if (iStatType == STAT_TYPE_BY_HOUR)
	{
		return PE_RET_OK;
	}

	return PE_RET_FAIL;

}

int ExportData(FILETIME &ftStartTime,FILETIME &ftEndTime,int iStatType,TCHAR *szFileName)
{
	if (iStatType == STAT_TYPE_UNKNOW)
	{
		return PE_RET_FAIL;
	}

	FILE *pLog = _tfopen(szFileName,_T("wt"));
	if (pLog == NULL)
	{
		return PE_RET_FAIL;
	}


	list<STAT_ITEM*> sentList;
	list<STAT_ITEM*> recvList;

	if (iStatType == STAT_TYPE_BY_YEAR)
	{
		sentList = 	g_YearSentStatList;
		recvList = g_YearRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_MONTH)
	{
		sentList = 	g_MonthSentStatList;
		recvList = g_MonthRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_DAY)
	{
		sentList = 	g_DaySentStatList;
		recvList = g_DayRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_HOUR)
	{
		sentList = 	g_HourSentStatList;
		recvList = g_HourRecvStatList;
	}

	//Export data to csv
	TCHAR szTime[100];
	time_t tmp = 0;
	list<STAT_ITEM*>::iterator it;
	for (it = sentList.begin(); it != sentList.end(); ++it)
	{ 
		STAT_ITEM *pItem = (STAT_ITEM*)*it;
		SystemTime2TimeT(pItem->stSortTime,tmp);
		GetTimeString(iStatType,tmp,szTime);
		_ftprintf(pLog,_T("Time:%s,Sent:%d,Received:%d,\n"),szTime,pItem->SentCount,pItem->RecvCount);
	}

	for (it = recvList.begin(); it != recvList.end(); ++it)
	{ 
		STAT_ITEM *pItem = (STAT_ITEM*)*it;
		SystemTime2TimeT(pItem->stSortTime,tmp);
		GetTimeString(iStatType,tmp,szTime);
		_ftprintf(pLog,_T("Time:%s,Sent:%d,Received:%d,\n"),szTime,pItem->SentCount,pItem->RecvCount);
	}
	

	//Generate Top Sender/Receiver data

	list<SENDER_ITEM*>::iterator itSender;
	for (itSender = g_TopSenderList.begin(); itSender != g_TopSenderList.end(); ++itSender)
	{ 
		SENDER_ITEM *pItem = (SENDER_ITEM*)*itSender;
		_ftprintf(pLog,_T("Sender:%s,%d,\n"),pItem->szMail,pItem->dwMailCount);
	}

	list<SENDER_ITEM*>::iterator itReceiver;
	for (itReceiver = g_TopReceverList.begin(); itReceiver != g_TopReceverList.end(); ++itReceiver)
	{ 
		SENDER_ITEM *pItem = (SENDER_ITEM*)*itReceiver;
		_ftprintf(pLog,_T("Receiver:%s,%d,\n"),pItem->szMail,pItem->dwMailCount);
	}

	fclose(pLog);

	return PE_RET_OK;

}



int GenChartData(FILETIME &ftStartTime,FILETIME &ftEndTime,int iStatType)
{
	if (iStatType == STAT_TYPE_UNKNOW)
	{
		return PE_RET_FAIL;
	}

	if (g_pChartData)
	{
		free(g_pChartData);
	}

	list<STAT_ITEM*> sentList;
	list<STAT_ITEM*> recvList;

	if (iStatType == STAT_TYPE_BY_YEAR)
	{
		sentList = 	g_YearSentStatList;
		recvList = g_YearRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_MONTH)
	{
		sentList = 	g_MonthSentStatList;
		recvList = g_MonthRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_DAY)
	{
		sentList = 	g_DaySentStatList;
		recvList = g_DayRecvStatList;
	}
	else if (iStatType == STAT_TYPE_BY_HOUR)
	{
		sentList = 	g_HourSentStatList;
		recvList = g_HourRecvStatList;
	}

	//Generate general chart data
	CString sGeneralLabel = _T("var GeneralLabel = [");
	CString sDataSent = 	_T("var DataSent = [");
	CString sDataReceived = _T("var DataReceived = [");

	FILETIME ft = ftStartTime;
	time_t curTime,maxTime;
	memcpy(&curTime,&ftStartTime,sizeof(FILETIME));
	memcpy(&maxTime,&ftEndTime,sizeof(FILETIME));

	if (curTime == 0 && maxTime == 0)
	{
		list<STAT_ITEM*>::iterator it;
		for (it = sentList.begin(); it != sentList.end(); ++it)
		{ 
			STAT_ITEM *pItem = (STAT_ITEM*)*it;
			time_t tmp = 0;
			SystemTime2TimeT(pItem->stSortTime,tmp);
			if (curTime == 0)
			{
				curTime = tmp;
			}

			if (curTime < tmp)
			{
				curTime = tmp;
			}

			if (tmp >= maxTime)
			{
				maxTime = tmp;
			}
		}

		for (it = recvList.begin(); it != recvList.end(); ++it)
		{ 
			STAT_ITEM *pItem = (STAT_ITEM*)*it;
			time_t tmp = 0;
			SystemTime2TimeT(pItem->stSortTime,tmp);
			if (curTime == 0)
			{
				curTime = tmp;
			}

			if (curTime < tmp)
			{
				curTime = tmp;
			}

			if (tmp >= maxTime)
			{
				maxTime = tmp;
			}
		}
	}


	for (; curTime <= maxTime; curTime = GetNextTime(iStatType,curTime))
	{
		TCHAR szTime[255];
		GetTimeString(iStatType,curTime,szTime);
		sGeneralLabel += szTime;
		sGeneralLabel += _T(",");

		SYSTEMTIME stTmp;
		TimeT2SystemTime(curTime,stTmp);

		int iFound = 0;

		list<STAT_ITEM*>::iterator it;
		for (it = sentList.begin(); it != sentList.end(); ++it)
		{ 
			STAT_ITEM *pItem = (STAT_ITEM*)*it;
			if (IsSameRange(iStatType,pItem->stSortTime,stTmp) == PE_RET_OK)
			{
				TCHAR szSent[255];
				_stprintf(szSent,_T("%d,"),pItem->SentCount);
				sDataSent += szSent;
				iFound = 1;
				break;
			}
		}

		if (!iFound)
		{
			sDataSent += _T("0,");
		}

		iFound = 0;
		for (it = recvList.begin(); it != recvList.end(); ++it)
		{ 
			STAT_ITEM *pItem = (STAT_ITEM*)*it;
			if (IsSameRange(iStatType,pItem->stSortTime,stTmp) == PE_RET_OK)
			{
				TCHAR szRecv[255];
				_stprintf(szRecv,_T("%d,"),pItem->RecvCount);
				sDataReceived += szRecv;
				iFound = 1;
				break;
			}
		}

		if (!iFound)
		{
			sDataReceived += _T("0,");
		}

	}

	sGeneralLabel += _T("];\r\n");
	sDataSent += 	_T("];\r\n");
	sDataReceived += _T("];\r\n");

	//Generate Top Sender/Receiver data
	CString sSenderLabel = _T("var SenderLabel = [");
	CString sDataSender = _T("var DataSender = [");
	CString sReceiverLabel = _T("var ReceiverLabel = [");
	CString sDataReceiver = _T("var DataReceiver = [");

	list<SENDER_ITEM*>::iterator itSender;
	int iMaxCount = 0;
	for (itSender = g_TopSenderList.begin(); itSender != g_TopSenderList.end(); ++itSender)
	{ 
		if (++iMaxCount > 10)
		{
			break;
		}

		SENDER_ITEM *pItem = (SENDER_ITEM*)*itSender;
		CString sName = pItem->szMail;
		int iPos = sName.Find(_T("@"));
		if (iPos > 0)
		{
			sName = sName.Left(iPos);
		}
		
		if (sName.GetLength() > 20)
		{
			sName = sName.Left(20);
		}

		sName.Replace(_T("\""),_T(""));
		sName.Replace(_T("\'"),_T(""));

		sSenderLabel += _T("\"");
		sSenderLabel += sName;
		sSenderLabel += _T("\",");

		TCHAR szCount[255];
		_stprintf(szCount,_T("%d,"),pItem->dwMailCount);
		sDataSender += szCount;	
	}
	sSenderLabel += _T("];\r\n");
	sDataSender += _T("];\r\n");

	list<SENDER_ITEM*>::iterator itReceiver;
	iMaxCount = 0;
	for (itReceiver = g_TopReceverList.begin(); itReceiver != g_TopReceverList.end(); ++itReceiver)
	{ 
		if (++iMaxCount > 10)
		{
			break;
		}

		SENDER_ITEM *pItem = (SENDER_ITEM*)*itReceiver;
		CString sName = pItem->szMail;
		int iPos = sName.Find(_T("@"));
		if (iPos > 0)
		{
			sName = sName.Left(iPos);
		}
		
		if (sName.GetLength() > 20)
		{
			sName = sName.Left(20);
		}

		sName.Replace(_T("\""),_T(""));
		sName.Replace(_T("\'"),_T(""));

		sReceiverLabel += _T("\"");
		sReceiverLabel += sName;
		sReceiverLabel += _T("\",");

		TCHAR szCount[255];
		_stprintf(szCount,_T("%d,"),pItem->dwMailCount);
		sDataReceiver += szCount;	
	}
	sReceiverLabel += _T("];\r\n");
	sDataReceiver += _T("];\r\n");

	//copy generated data to buffer
	g_pChartData = (TCHAR*)calloc(PE_MAX_BUF_LEN,sizeof(TCHAR));
	TCHAR *szData = g_pChartData;
	_tcscpy(szData,sGeneralLabel.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sDataSent.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sDataReceived.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sSenderLabel.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sDataSender.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sReceiverLabel.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	_tcscpy(szData,sDataReceiver.GetBuffer());
	szData += _tcslen(szData);
	//szData += 1;

	sGeneralLabel.ReleaseBuffer();
	sDataSent.ReleaseBuffer();
	sDataReceived.ReleaseBuffer();
	sSenderLabel.ReleaseBuffer();
	sDataSender.ReleaseBuffer();
	sReceiverLabel.ReleaseBuffer();
	sDataReceiver.ReleaseBuffer();

	return PE_RET_OK;

}


int StartMiniHttpd()
{
	g_miniHttpd = new CMiniHttpd();
	g_miniHttpd->m_nPort = 20000;

	while( g_miniHttpd->Create(g_miniHttpd->m_nPort) == FALSE )
	{
		g_miniHttpd->m_nPort++;
		if (g_miniHttpd->m_nPort > 65535 )
		{
			break;
		}
	}

	if(g_miniHttpd->Listen()==FALSE)
	{
		return 0;
	}

	g_iPCPort = g_miniHttpd->m_nPort;

	return 0;
}





